﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Security.AccessControl;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using Sunlight.Dispatch.Data;

namespace Sunlight.Dispatch.Tools {
    public static class Utils {
        /// <summary>
        /// 获取AppSetting的配置
        /// </summary>
        /// <param name="appSettingKey">AppSetting Key</param>
        /// <returns>队列名称</returns>
        public static string GetAppStringByKey(string appSettingKey) {
            var reader = new AppSettingsReader();
            var queueName = reader.GetValue(appSettingKey, typeof(string));

            if(queueName == null)
                throw new KeyNotFoundException($"配置文件中，{appSettingKey}配置节未找到，请重新配置");

            return queueName.ToString();
        }

        /// <summary>
        /// 获取数据库连接字符串
        /// </summary>
        /// <param name="connectionName">连接名称</param>
        /// <returns>队列名称</returns>
        public static string GetConnectionStringByName(string connectionName) {
            if(ConfigurationManager.ConnectionStrings.Count <= 0)
                throw new KeyNotFoundException("没有任何的ConnectionString配置");
            if(ConfigurationManager.ConnectionStrings[connectionName] == null)
                throw new KeyNotFoundException($"没有任何的{connectionName}配置");
            return ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
        }

        /// <summary>
        /// 测试数据库是否可以正常连接
        /// </summary>
        /// <param name="msg">连接数据库失败时的提示信息</param>
        /// <param name="connectionString">连接字符串</param>
        /// <returns>是否连接成功</returns>
        public static bool IsCanConnect(out string msg, string connectionString) {
            if(string.IsNullOrEmpty(connectionString))
                throw new Exception("IsCanConnect Parameter is not null");
            msg = string.Empty;
            var db = DbHelper.GetDbHelp(connectionString);
            try {
                using(var conn = db.CreateDbConnection()) {
                    conn.Open();
                }

                return true;
            } catch(Exception ex) {
                var stringBuilder = new StringBuilder();
                stringBuilder.AppendLine(connectionString);
                stringBuilder.AppendLine(ex.Message);
                msg = stringBuilder.ToString();
                return false;
            }
        }

        /// <summary>
        /// 格式化XML文件
        /// </summary>
        /// <param name="xml">XML报文</param>
        /// <returns>格式化的报文</returns>
        public static string FormatXml(object xml) {
            if(xml == null)
                return string.Empty;
            XmlDocument xd;
            if(xml is XmlDocument) {
                xd = xml as XmlDocument;
            } else {
                xd = new XmlDocument();
                xd.LoadXml(xml.ToString());
            }
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);
            XmlTextWriter xtw = null;
            try {
                xtw = new XmlTextWriter(sw);
                xtw.Formatting = Formatting.Indented;
                xtw.Indentation = 1;
                xtw.IndentChar = '\t';
                xd.WriteTo(xtw);
            } finally {
                if(xtw != null)
                    xtw.Close();
            }
            return sb.ToString();
        }

        /// <summary>
        /// 单实例程序控制，每次只能启动一个程序
        /// </summary>
        /// <returns>是否可以打开</returns>
        public static bool HasRunning() {
            Process currentProcess = Process.GetCurrentProcess();
            Process[] processCollection = Process.GetProcessesByName(currentProcess.ProcessName);
            foreach(Process p in processCollection) {
                if(p.Id == currentProcess.Id) {
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 获取本机的IP地址
        /// </summary>
        /// <returns>返回本机的IP 地址</returns>
        public static List<IPAddress> GetHostIpList() {
            string name = Dns.GetHostName();
            IPAddress[] ipadrlist = Dns.GetHostAddresses(name);

            var interNetwork = new List<IPAddress>();
            foreach(IPAddress ipa in ipadrlist) {
                if(ipa.AddressFamily == AddressFamily.InterNetwork)
                    interNetwork.Add(ipa);
            }

            return interNetwork;
        }

        /// <summary>
        /// 获取事务Id
        /// </summary>
        /// <param name="xml">报文</param>
        /// <returns>事务Id</returns>
        public static string GetBizTransactionId(string xml) {
            string bizTransactionIdElement = string.Empty;
            try {
                MatchCollection collection = Regex.Matches(xml, @"<BIZTRANSACTIONID.*>?.*<?\/BIZTRANSACTIONID>");
                if(collection.Count > 1)
                    throw new Exception("报文解析BIZTRANSACTIONID出错");

                bizTransactionIdElement = collection[0].Value;
                if(string.IsNullOrEmpty(bizTransactionIdElement))
                    throw new Exception("报文解析BIZTRANSACTIONID出错");
                var bizTransactionId = bizTransactionIdElement.Replace("<BIZTRANSACTIONID>", "").Replace("</BIZTRANSACTIONID>", "");
                bizTransactionId = bizTransactionId.Replace("<BIZTRANSACTIONID type=\"string\">", "");

                return bizTransactionId;
            } catch(Exception ex) {
                LoggerUtils.Error(ex.Message);
                //解析出错后，将整个BIZTRANSACTIONID标签进行存储
                return bizTransactionIdElement;
            }
        }

        /// <summary>
        /// 将系统配置序列化文件中
        /// </summary>
        /// <param name="config"></param>
        public static void Serialize(SystemConfig config) {
            if(config == null)
                throw new Exception("序列化配置不存在，请检查");
            IFormatter serializer = new BinaryFormatter();
            var systemPath = Environment.GetEnvironmentVariable("ProgramFiles");
            var defaultPath = string.IsNullOrEmpty(systemPath) ? "c:\\" : systemPath;
            var ini = Path.Combine(defaultPath, "Dispatch\\systemConfig.ini");
            var path = Path.GetDirectoryName(ini);
            if(string.IsNullOrEmpty(path))
                return;
            if(!Directory.Exists(path))
                Directory.CreateDirectory(path);
            FileStream saveFile = new FileStream(ini, FileMode.Create, FileAccess.Write);
            serializer.Serialize(saveFile, config);
            saveFile.Close();
        }

        /// <summary>
        /// 将系统配置反序列化为对象
        /// </summary>
        public static SystemConfig DeSerialize() {
            IFormatter serializer = new BinaryFormatter();
            var systemPath = Environment.GetEnvironmentVariable("ProgramFiles");
            var defaultPath = string.IsNullOrEmpty(systemPath) ? "c:\\" : systemPath;
            var ini = Path.Combine(defaultPath, "Dispatch\\systemConfig.ini");
            if(!File.Exists(ini))
                File.Create(ini, 512);
            FileStream loadFile = new FileStream(ini, FileMode.Open, FileAccess.Read);
            var config = serializer.Deserialize(loadFile) as SystemConfig;
            return config;
        }

        /// <summary>
        /// 获取系统环境所在的目录
        /// </summary>
        public static string GetDefaultEnvironmentPath() {
            return Environment.GetEnvironmentVariable("ProgramFiles");
        }

        /// <summary>
        /// 唯一键
        /// </summary>
        /// <returns>格式化GUID</returns>
        public static string NewGuid() {
            return Guid.NewGuid().ToString().ToUpper().Replace("-", "");
        }

        /// <summary>
        /// 创建数据库并初始化配置
        /// </summary>
        /// <param name="connection">连接对象</param>
        /// <param name="absolutePath">绝对路径</param>
        /// <param name="type">存储类型，对应SQLiteStoryPathTypeEnum枚举的值</param>
        public static void CreateDataBaseAndInit(this SQLiteConnection connection, string absolutePath, int type) {
            var path = Path.GetDirectoryName(absolutePath);
            if(string.IsNullOrEmpty(path))
                throw new Exception("创建数据库时，所选择路径不存在");
            if(type != (int)SQLiteStoryPathTypeEnum.自定义 && type != (int)SQLiteStoryPathTypeEnum.默认)
                throw new Exception("数据库存储路径方式无效，请重新指定");
            if(!Directory.Exists(path))
                Directory.CreateDirectory(path);
            SQLiteConnection.CreateFile(absolutePath);

            using(var conn = new SQLiteConnection(string.Format($"Data Source={absolutePath};Version=3;"))) {
                conn.Open();
                //创建连接字符串存储表
                string sql = "create table ConnectStringConfigTb (Id varchar(33),Name varchar(40), ConnectString varchar(200))";
                SQLiteCommand command = new SQLiteCommand(sql, conn);
                command.ExecuteNonQuery();
            }

            //将配置序列化之文件中
            Serialize(new SystemConfig {
                SqliteStoryPath = absolutePath,
                SqliteStoryPathType = type
            });
        }
    }
}
